Struct = {}
Struct.mode = {}

function Struct:destroyInstance()
  _G.Struct = false
end

function Struct:getInstance()
  local o = _G.Struct
  if o then
    return o
  end
  o = {}
  _G.Struct = o
  setmetatable(o, self)
  self.__index = self
  return o
end

local BYTE = "BYTE"
local BOOL = "BOOL"
local WORD = "WORD"
local INT = "INT"
local DWORD = "DWORD"
local FLOAT = "FLOAT"
local DOUBLE = "DOUBLE"
local INT64 = "INT64"
local UINT64 = "UINT64"
local String = "String"
local WString = "WString"
local SYSTEMTIME = "SYSTEMTIME"
local LIST = "LIST"
local STRUCT = "STRUCT"
    
-- 用户登录
Struct.mode['CMD_CS_UserLoginHall'] = function()
 
    return {
        {name = "iVersion", value = 0, type = INT, len = 4 },          -- 版本号
        {name = "iAppId", value = 0, type = INT, len = 4 },            -- 游戏AppID(捕鱼=1; 三公=2; 估计牛牛是=5;)
        {name = "szName", value = nil, type = String, len = 33 },      -- 帐号
        {name = "szPwd", value = 0, type = String, len = 33 },         -- 密码
        {name = "szIp", value = 0, type = String, len = 20 },          -- IP地址(服务器用)
        {name = "iTrenchId", value = 0, type = INT, len = 4 },         -- 渠道【推广公司：比如腾讯，360，安桌市场等等】(0:本公司; )渠道增加把注释也加上。
        {name = "iPlatformNo", value = 0, type = INT, len = 4 },       -- 1=手机;2=PC;3=网页;
        {name = "szMachineCode", value = 0, type = String, len = 33 }  -- 机器序列号
    }
end

-- 用户登录成功
Struct.mode['CMD_SC_AgentUserLoginInfo'] = function()

    return {
        {name = "iRet", value = 0, type = INT, len = 4 },                          -- 返回状态(0:成功;1:)
        {name = "llUserID", value = nil, type = INT64, len = 8 },                  -- 用户ID
        {name = "szName", value = nil, type = String, len = 33 },                  -- 帐号
        {name = "szNickName", value = nil, type = String, len = 33 },              -- 昵稱
        {name = "dtForbidEnterTime", value = nil, type = SYSTEMTIME, len = 24 },   -- 禁止进入时间
        {name = "szResText", value = nil, type = String, len = 64 },               -- 返回内容说明
    }
end    

-- 游戏信息
Struct.mode['CMD_SC_HALLGAME_LIST'] = function()

    return {
        {name = "nGameId", value = 0, type = INT, len = 4 },                 -- 游戏ID
        {name = "szGameName", value = nil, type = String, len = 32 },        -- 游戏名字
        {name = "szAndrDownAddr", value = nil, type = String, len = 512 },   -- 游戏安卓下载地址
        {name = "szAppDownAddr", value = nil, type = String, len = 512 },    -- 游戏苹果下载地址
        {name = "szPacketName", value = nil, type = String, len = 32 },      -- 包名
        {name = "szVersionNO", value = nil, type = String, len = 32 },       -- 版本号
        {name = "szGameIntro", value = nil, type = String, len = 256 } ,     -- 描述长度
        {name = "nStartOrder", value = 0, type = INT, len = 4 },             -- 顺序
    }
end    

-- 登录错误
Struct.mode['CMD_SC_AgentUserLoginFail'] = function()

    return {
        {name = "iRet", value = 0, type = INT, len = 4 },               -- 返回状态(0:成功;!0:失败)
        {name = "szResText", value = nil, type = String, len = 64 }    -- 返回内容说明
    }
end

-- 邮件
Struct.mode['CMD_MailInfo'] = function()

    return {
        {name = "iType", value = 0, type = INT, len = 4 },                    -- 操作状态(1=增加，2=已读，3=删除，4=查询)
        {name = "iError", value = 0, type = INT, len = 4 },                   -- 错误码(0=成功，1=失败)
        {name = "iRet", value = 0, type = INT, len = 4 },                     -- 成功返回0 
        {name = "szRet", value = 0, type = String, len = 64 },                -- 返回提示
        {name = "iReadReceipt", value = nil, type = INT, len = 4 },           -- 收件人已读回执
        {name = "szSenderName", value = nil, type = String, len = 33 },       -- 发件人昵称
        {name = "szAddresseeName", value = nil, type = String, len = 33 },    -- 收件人昵称
        {name = "dtSendTime", value = nil, type = SYSTEMTIME, len = 33 },     -- 发件时间
        {name = "llRid", value = nil, type = INT64, len = 33 },               -- 邮件ID
        {name = "llUid", value = nil, type = String, len = 20 },              -- 发件人ID
        {name = "llTid", value = 0, type = INT, len = 4 },                    -- 收件人ID
        {name = "szText", value = 0, type = INT, len = 4 },                   -- 正文
        {name = "iMailType", value = nil, type = String, len = 33 }           -- 0: 默认系统,1:分享金币,2:点卡充值
       
    }
end    
    

-- 用户注册
Struct.mode['CMD_CS_HallUserRegister'] = function()

    return {
        {name = "iVersion", value = 0, type = INT, len = 4 },                 -- 版本号
        {name = "iAppId", value = 0, type = INT, len = 4 },                   -- 游戏AppID(捕鱼=1; 三公=2; 估计牛牛是=5;)
        {name = "iPlatformNo", value = 0, type = INT, len = 4 },              -- 1=手机;2=PC;3=网页;
        {name = "iEnterMode", value = 0, type = INT, len = 4 },               -- 进入方式(0:用户名密码进入[正常输入用户名密码登录]，1:快速进入[游客登录])
        {name = "szMachineCode", value = nil, type = String, len = 33 },      -- 机器序列号
        {name = "szName", value = nil, type = String, len = 33 },             -- 帐号
        {name = "szPwd", value = nil, type = String, len = 33 },              -- 昵称
        {name = "szNickName", value = nil, type = String, len = 33 },         -- IP地址(服务器用)
        {name = "szIp", value = nil, type = String, len = 20 },               -- IP地址(服务器用)
        {name = "iSex", value = 0, type = INT, len = 4 },                     -- 性别
        {name = "iTrenchId", value = 0, type = INT, len = 4 },                -- 渠道【推广公司：比如腾讯，360，安桌市场等等】(0:本公司; )渠道增加把注释也加上。
        {name = "szAgentCode", value = nil, type = String, len = 33 }         -- 推荐人编码
       
    }
end    

function Struct:setValue(data, key, value)
    for var = 1, #data do
        local cell = data[var]
        if cell.name == key then
            cell.value = value
            break
        end
    end
end

function Struct:getBodyData( name )
    if not Struct.mode[name] then
        return nil
    end
    local data = Struct.mode[name]()
    return data
end

function Struct:writeBody(packout, structData)

    for var = 1, #structData do
      local cell = structData[var]
      if cell.type == BYTE then
        packout:LuaWriteByte(cell.value)
      elseif cell.type == BOOL then
        packout:LuaWriteBool(cell.value)
      elseif cell.type == WORD then
        packout:LuaWriteWord(cell.value)
      elseif cell.type == INT then
        packout:LuaWriteInt(cell.value)
      elseif cell.type == INT then
        packout:LuaWriteInt(cell.value)
      elseif cell.type == DWORD then
        packout:LuaWriteDword(cell.value)
      elseif cell.type == FLOAT then
        packout:LuaWriteFloat(cell.value)
      elseif cell.type == DOUBLE then
        packout:LuaWriteDouble(cell.value)
      elseif cell.type == String and cell.len and cell.len > 0 then
        packout:LuaWriteString(cell.value,cell.len)
      elseif cell.type == WString and cell.len and cell.len > 0 then
        packout:LuaWriteWString(cell.value,cell.len)
      elseif cell.type == SYSTEMTIME then
        packout:LuaWriteInt(0)
        packout:LuaWriteInt(0)
        packout:LuaWriteInt(0)
        packout:LuaWriteInt(0)
        packout:LuaWriteInt(0)
        packout:LuaWriteInt(0)
      end
      if cell.type == LIST then
        for idx = 1, #cell.value do
          self:writeBody(packout, cell.value[idx])
        end
      end
      if cell.type == STRUCT then
        self:writeBody(packout, cell.value)
      end
    end
end

 
function Struct:readBody(packin, structData)

    local returndata = {}
    for var = 1, #structData do
      local returncell
      local cell = structData[var]
      if cell.type == BYTE then
         cell.value = packin:LuaReadByte()
         returncell = cell.value
      elseif cell.type == BOOL then
         cell.value = packin:LuaReadBool()
         returncell = cell.value
      elseif cell.type == WORD then
         cell.value = packin:LuaReadWord()
         returncell = cell.value
      elseif cell.type == INT then
         cell.value = packin:LuaReadInt()
         returncell = cell.value
      elseif cell.type == DWORD then
         cell.value = packin:LuaReadDword()
         returncell = cell.value
      elseif cell.type == FLOAT then
         cell.value = packin:LuaReadFloat()
         returncell = cell.value     
      elseif cell.type == DOUBLE then
         cell.value = packin:LuaReadDouble()
         returncell = cell.value 
      elseif cell.type == INT64 then
         cell.value = packin:LuaReadINT64()
         returncell = cell.value    
      elseif cell.type == UINT64 then
         cell.value = packin:LuaReadUINT64()
         returncell = cell.value   
      elseif cell.type == String  and cell.len and cell.len > 0 then
         cell.value = packin:LuaReadString(cell.len)
         returncell = cell.value    
      elseif cell.type == WString  and cell.len and cell.len > 0 then
         cell.value = packin:LuaReadWString(cell.len)
         returncell = cell.value         
      elseif cell.type == LIST then
        if cell.len == 1 then
           cell.value = packin:LuaReadByte()
        elseif cell.len == 2 then
           cell.value = packin:LuaReadWord()
        elseif cell.len == 4 then
           cell.value = packin:LuaReadInt()
        elseif cell.len == 8 then
           cell.value = tonumber(packin:LuaReadUINT64())
        end
        local count = cell.value
        local datalist = {}
        if Struct.mode[cell.structname] and count > 0 then
          for var = 1, count do
            local tructdata = Struct.mode[cell.structname]()
            local data = self:readBody(packin, tructdata)
            table.insert(datalist, data)
          end
        end
        returncell = datalist
      elseif cell.type == STRUCT then
        if cell.structname and Struct.mode[cell.structname] then
          local tructdata = Struct.mode[cell.structname]()
          local data = self:readBody(packin, tructdata)
          returncell = data
        end
      elseif cell.type == SYSTEMTIME then
        local timedata = {}
        timedata.iYear = packin:LuaReadInt()
        timedata.iMonth = packin:LuaReadInt()
        timedata.iDay = packin:LuaReadInt()
        timedata.iHour = packin:LuaReadInt()
        timedata.iMinute = packin:LuaReadInt()
        timedata.iSecond = packin:LuaReadInt()
     --   timedata.wMilliseconds = packin:LuaReadWord()
        returncell = timedata
      end
      returndata[cell.name] = returncell
      if cell.isgoonvalue and cell.value ~= cell.goonvalue then
        break
      end
    end
    return returndata
end

